﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace MetaSharp.Transformation.Tests.Patterns
{
	public class OneOrMoreTests
	{
        [Fact]
		public async Task OneOrMoreFailsWithEmptyStream()
		{
			var p = Pattern.OneOrMore(Pattern.Any());
            var m = await Pattern.Match(p, "");
            Assert.False(m.Matched);
		}

        [Fact]
        public async Task FailureToMatchFails()
        {
            var p = Pattern.OneOrMore(Pattern.Value('b'));
            var m = await Pattern.Match(p, "a");
            Assert.False(m.Matched);
        }

        [Fact]
        public async Task FailureToMatchDoesNotConsumeInput()
        {
            var p = Pattern.OneOrMore(Pattern.Value('b'));
            var m = await Pattern.Match(p, "a");
            Assert.Equal(0, m.End.Stream.Index);
        }


        [Fact]
		public async Task SingleMatchSucceeds()
		{
            var p = Pattern.OneOrMore(Pattern.Any());
            var m = await Pattern.Match(p, "a");
            Assert.Equal(new object[] { 'a' }, m.Value);
		}

        [Fact]
        public async Task MatchingConsumesInput()
        {
            var p = Pattern.OneOrMore(Pattern.Any());
            var m = await Pattern.Match(p, "a");
            Assert.Equal(1, m.End.Stream.Index);
        }

        [Fact]
        public async Task OneOrMoreProducesASetOfValues()
        {
            var p = Pattern.OneOrMore(Pattern.Any());
            var m = await Pattern.Match(p, "aaa");
            Assert.IsAssignableFrom<IEnumerable>(m.Value);
        }

        [Fact]
		public async Task MultipleMatchesSucceed()
		{
            var p = Pattern.OneOrMore(Pattern.Any());
            var m = await Pattern.Match(p, "abc");
            Assert.Equal(new object[] { 'a', 'b', 'c' } , m.Value);
		}

        [Fact]
		public async Task MatchesAndReadsToCorrectPosition()
		{
            var p = Pattern.Rule(Pattern.OneOrMore(Pattern.Value('a')));
            var m = await Pattern.Match(p, "aabb");
            var trace = m.Trace();
            Assert.Equal(SourceSpan.From(0, 2), trace);
		}
	}
}
